package com.pan.admin.module.loanProduct.service.impl;

import com.gitee.apanlh.util.algorithm.encrypt.symmetric.AES;
import com.gitee.apanlh.util.base.ArrayUtils;
import com.gitee.apanlh.util.base.CollUtils;
import com.gitee.apanlh.util.base.Eq;
import com.gitee.apanlh.util.base.IteratorUtils;
import com.gitee.apanlh.util.base.MapUtils;
import com.gitee.apanlh.util.dataformat.JsonUtils;
import com.gitee.apanlh.util.encode.HexUtils;
import com.gitee.apanlh.util.net.http.HttpClientBuilder;
import com.gitee.apanlh.util.net.http.HttpResponse;
import com.gitee.apanlh.util.reflection.ClassConvertUtils;
import com.gitee.apanlh.util.valid.Assert;
import com.gitee.apanlh.util.valid.ValidParam;
import com.gitee.apanlh.web.http.HttpMethod;
import com.pan.admin.cache.DistrictCache;
import com.pan.admin.common.annotation.DataScope;
import com.pan.admin.common.annotation.DataSource;
import com.pan.admin.common.core.domain.entity.SysUser;
import com.pan.admin.common.enums.DataSourceType;
import com.pan.admin.common.exception.ServiceException;
import com.pan.admin.common.utils.DateUtils;
import com.pan.admin.common.utils.SecurityUtils;
import com.pan.admin.common.utils.StringUtils;
import com.pan.admin.common.utils.spring.SpringUtils;
import com.pan.admin.meta.MetaPlanOnline;
import com.pan.admin.module.area.entity.LoanProductPlanArea;
import com.pan.admin.module.area.service.LoanProductPlanAreaService;
import com.pan.admin.module.common.entity.DistrictPO;
import com.pan.admin.module.loanProduct.dao.LoanProductPlanDao;
import com.pan.admin.module.loanProduct.entity.LoanProduct;
import com.pan.admin.module.loanProduct.entity.LoanProductPlan;
import com.pan.admin.module.loanProduct.entity.TestA0001;
import com.pan.admin.module.loanProduct.entity.po.OrgPlanApplyPO;
import com.pan.admin.module.loanProduct.entity.qo.LoanProductPlanKeywordQO;
import com.pan.admin.module.loanProduct.entity.qo.OrgPlanApplyQO;
import com.pan.admin.module.loanProduct.entity.vo.LoanProductPlanTestVO;
import com.pan.admin.module.loanProduct.entity.vo.LoanProductPlanVO;
import com.pan.admin.module.loanProduct.enums.PlanTypeEnum;
import com.pan.admin.module.loanProduct.service.LoanProductPlanService;
import com.pan.admin.module.loanProduct.service.LoanProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;

/**
 * 配置机构计划Service业务层处理
 *
 * @author ts
 * @date 2023-12-27
 */
@Service
public class LoanProductPlanServiceImpl implements LoanProductPlanService {

    @Autowired
    private LoanProductPlanDao loanProductPlanDao;
    @Autowired
    private LoanProductPlanAreaService loanProductPlanAreaService;
    @Autowired
    private LoanProductService loanProductService;
    @Autowired
    private MetaPlanOnline metaPlanOnline;

    @Override
    @Transactional(readOnly = true)
    public List<Map<String, Object>> listLoanProductPlan(List<Long> loanProductId, String keyword) {
        return this.loanProductPlanDao.listLoanProductPlan(loanProductId, keyword);
    }

    @Override
    @Transactional(readOnly = true)
    @DataScope(deptAlias = "d", userAlias = "u")
    public List<Map<String, Object>> listLoanProductPlanWithDataScope(LoanProductPlanKeywordQO keyword) {
        return this.loanProductPlanDao.listLoanProductPlanWithDataScope(keyword);
    }

    @Override
    @Transactional(readOnly = true)
    public List<LoanProductPlan> listAll() {
        return loanProductPlanDao.listAll();
    }

    @Override
    @Transactional(readOnly = true)
    @DataSource(DataSourceType.SLAVE)
    public List<LoanProductPlan> listAllSlave() {
        return loanProductPlanDao.listAll();
    }

    @Override
    @Transactional(readOnly = true)
    @DataScope(deptAlias = "d", userAlias = "u")
    public LoanProductPlan getByIdWithDataScope(PlanTypeEnum planTypeEnum, LoanProductPlan loanProductPlanId) {
        Assert.isNotNull(planTypeEnum);

        LoanProductPlan loanProductPlan = loanProductPlanDao.getByIdWithDataScope(loanProductPlanId);
        if (ValidParam.isNull(loanProductPlan)){
            return null;
        }
        Assert.isTrue(Objects.equals(loanProductPlan.getPlanType(), planTypeEnum.getValue()));

        //  合并编码-[父编码,子编码]
        List<String> margeList = CollUtils.newArrayList();
        //  获取搜索关联的子集编码
        List<String> listAreaByPlanId = loanProductPlanAreaService.getAreaCodeByPlanId(loanProductPlanId.getId());

        //  根据子集编码搜索父类编码合成
        IteratorUtils.array(listAreaByPlanId, code -> {
            DistrictPO districtPO = DistrictCache.getByCode(code);
            String pCode = districtPO.getPCode();
            //  改变原有pCode值,县级市合并为市级
            margeList.add(pCode.substring(0, 2) + "0000" + "," + code);
        });
        loanProductPlan.setArea(margeList);
        return loanProductPlan;
    }

    @Override
    @Transactional(readOnly = true)
    @DataScope(deptAlias = "d", userAlias = "u")
    public List<LoanProductPlan> listWithDataScope(PlanTypeEnum planTypeEnum, LoanProductPlan loanProductPlanVO) {
        Assert.isNotNull(planTypeEnum);
        loanProductPlanVO.setPlanType(planTypeEnum.getValue());

        List<LoanProductPlan> list = loanProductPlanDao.listWithDataScope(loanProductPlanVO);
        if (ValidParam.isEmpty(list)) {
            return list;
        }

        //  获取上线计划缓存
        List<String> listOnlineCache = metaPlanOnline.getCache();
        //  设置计划上线状态
        if (ValidParam.isNotEmpty(listOnlineCache)) {
            IteratorUtils.array(list, productPlan -> {
                Long productId = productPlan.getLoanProductId();
                //  是否属于本地crm计划
                if (ValidParam.isEmpty(productPlan.getApiDataExchange()) && ValidParam.isEmpty(productPlan.getApiApplyUrl())) {
                    productPlan.setHasOnline(true);
                    return ;
                }

                //  是否属于对方接入
                if (productPlan.getProviderType().equals(1)) {
                    productPlan.setHasOnline(true);
                    return ;
                }

                //  检测是否属于上线状态
                boolean hasOnline = metaPlanOnline.hasOnline(productId, listOnlineCache);
                productPlan.setHasOnline(hasOnline);
            });
        }

        //  查询关联地区
        List<Long> ids = CollUtils.toList(list, t -> t.getId());
        List<LoanProductPlanArea> planList = loanProductPlanAreaService.getByPlanIds(ids);

        //  关联地区
        IteratorUtils.array(list, item -> {
            //  建立新地区
            item.setAreaList(CollUtils.newArrayList());

            IteratorUtils.array(planList, item2 -> {
                if (Objects.equals(item.getId(), item2.getLoanProductPlanId())) {
                    List<LoanProductPlanArea> areaList = item.getAreaList();
                    areaList.add(item2);
                    item.setAreaList(areaList);
                }
            });
        });

        //  查询关联计划进件数量
        OrgPlanApplyQO orgPlanApplyQO = OrgPlanApplyQO.createByNowTime(ids);
        List<OrgPlanApplyPO> listApplyTotal = loanProductPlanDao.listApplyTotalByIds(orgPlanApplyQO);

        IteratorUtils.array(listApplyTotal, t -> {
            LoanProductPlan find = CollUtils.findOne(list, t2 -> Eq.object(t.getProductPlanId(), t2.getId()));
            if (ValidParam.isNotNull(find)) {
                find.setTodayApplyTotal(t.getApplyTotal());
            }
        });

        return list;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int insertLoanProductPlan(PlanTypeEnum planTypeEnum, LoanProductPlanVO loanProductPlanVO) {
        Assert.isNotNull(planTypeEnum);
        loanProductPlanVO.setPlanType(planTypeEnum.getValue());

        loanProductPlanVO.setCreateTime(DateUtils.getNowDate());
        loanProductPlanVO.setCreateBy(SecurityUtils.getUsername());
        //  默认状态禁用
        loanProductPlanVO.setStatus(0l);

        int row = loanProductPlanDao.insertLoanProductPlan(loanProductPlanVO);

        // 关联计划地区
        if (StringUtils.isNotEmpty(loanProductPlanVO.getArea())) {
            List<LoanProductPlanArea> list = new ArrayList<>();
            String[] idsArray = loanProductPlanVO.getArea().split(",");
            for (int i = 0; i < idsArray.length; i++) {
                DistrictPO area = DistrictCache.getByCode(idsArray[i]);
                Assert.isNotNullThrows(area, new RuntimeException("错误地区"));

                LoanProductPlanArea loanProductPlanArea = new LoanProductPlanArea();
                loanProductPlanArea.setLoanProductId(loanProductPlanVO.getLoanProductId());
                loanProductPlanArea.setLoanProductPlanId(loanProductPlanVO.getId());
                loanProductPlanArea.setAreaCode(idsArray[i]);
                loanProductPlanArea.setAreaName(area.getName());
                loanProductPlanVO.setCreateBy(SecurityUtils.getUsername());
                list.add(loanProductPlanArea);
            }
            loanProductPlanAreaService.insertListLoanProductPlanArea(list);
        }
        return row;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateLoanProductPlan(PlanTypeEnum planTypeEnum, LoanProductPlanVO loanProductPlanVO) {
        Assert.isNotNull(planTypeEnum);
        loanProductPlanVO.setPlanType(planTypeEnum.getValue());

        // 检查计划类型
        LoanProductPlan loanProductPlan = loanProductPlanDao.getById(loanProductPlanVO.getId());
        Assert.isNotNull(loanProductPlan);
        Assert.isTrue(Objects.equals(loanProductPlan.getPlanType(), planTypeEnum.getValue()));

        loanProductPlanVO.setUpdateBy(SecurityUtils.getUsername());
        loanProductPlanVO.setUpdateTime(DateUtils.getNowDate());

        // 获取所有区域数据id
        LoanProductPlanArea plan = new LoanProductPlanArea();
        plan.setLoanProductPlanId(loanProductPlanVO.getId());
        // 区域数据id
        List<LoanProductPlanArea> list = loanProductPlanAreaService.list(plan);
        if (!CollUtils.isEmpty(list)) {
            Long[] idList = new Long[list.size()];
            for (int j = 0; j < list.size(); j++) {
                idList[j] = list.get(j).getId();
            }
            if (!ArrayUtils.isEmpty(idList)) {
                // 删除之前的区域
                loanProductPlanAreaService.batchDeleteById(idList);
            }
        }

        // 多个区域的ids
        if (StringUtils.isNotEmpty(loanProductPlanVO.getArea())) {
            List<LoanProductPlanArea> planAreaList = new ArrayList<>();
            String[] idsArray = loanProductPlanVO.getArea().split(",");
            for (int i = 0; i < idsArray.length; i++) {
                DistrictPO area = DistrictCache.getByCode(idsArray[i]);
                Assert.isNotNullThrows(area, new RuntimeException("错误地区"));

                LoanProductPlanArea loanProductPlanArea = new LoanProductPlanArea();
                loanProductPlanArea.setLoanProductId(loanProductPlanVO.getLoanProductId());
                loanProductPlanArea.setLoanProductPlanId(loanProductPlanVO.getId());
                loanProductPlanArea.setAreaCode(idsArray[i]);
                loanProductPlanArea.setAreaName(area.getName());
                loanProductPlanArea.setCreateTime(new Date());
                loanProductPlanArea.setCreateBy(SecurityUtils.getUsername());
                planAreaList.add(loanProductPlanArea);
            }
            loanProductPlanAreaService.insertListLoanProductPlanArea(planAreaList);
        }
        return loanProductPlanDao.updateLoanProductPlan(loanProductPlanVO);
    }

    @Override
    public void checkDataScope(PlanTypeEnum type, Long id) {
        if (!SysUser.isAdmin(SecurityUtils.getUserId())) {
            LoanProductPlan loanProductPlan = new LoanProductPlan();
            loanProductPlan.setId(id);
            LoanProductPlan loanProductId = SpringUtils.getAopProxy(this).getByIdWithDataScope(type, loanProductPlan);
            if (loanProductId == null) {
                throw new ServiceException("没有权限访问用户数据！");
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int batchDeleteById(PlanTypeEnum planTypeEnum, Long[] ids) {
        Assert.isNotNull(planTypeEnum);

        Arrays.asList(ids).forEach(id -> {
            // 检查计划类型
            LoanProductPlan LoanProductPlan = loanProductPlanDao.getById(id);
            Assert.isNotNull(LoanProductPlan);
            Assert.isTrue(Objects.equals(LoanProductPlan.getPlanType(), planTypeEnum.getValue()));
        });

        for (int i = 0; i < ids.length; i++) {
            LoanProductPlanArea plan = new LoanProductPlanArea();
            plan.setLoanProductPlanId(ids[i]);
            List<LoanProductPlanArea> list = loanProductPlanAreaService.list(plan);
            Long[] idList = new Long[list.size()];

            for (int j = 0; j < list.size(); j++) {
                idList[j] = list.get(j).getId();
            }

            // 删除之前的区域
            if (!ArrayUtils.isEmpty(idList)) {
                loanProductPlanAreaService.batchDeleteById(idList);
            }
        }
        return loanProductPlanDao.batchDeleteById(ids);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateStatusById(PlanTypeEnum planTypeEnum, LoanProductPlanVO loanProductPlanVO) {
        Assert.isNotNull(planTypeEnum);

        // 检查计划类型
        LoanProductPlan loanProductPlan = loanProductPlanDao.getById(loanProductPlanVO.getId());
        Assert.isNotNull(loanProductPlan);
        Assert.isTrue(Objects.equals(loanProductPlan.getPlanType(), planTypeEnum.getValue()));

        loanProductPlanVO.setUpdateTime(DateUtils.getNowDate());
        loanProductPlanVO.setUpdateBy(SecurityUtils.getUsername());
        return loanProductPlanDao.updateStatusById(loanProductPlanVO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteById(PlanTypeEnum planTypeEnum, Long id) {
        Assert.isNotNull(planTypeEnum);

        // 检查计划类型
        LoanProductPlan LoanProductPlan = loanProductPlanDao.getById(id);
        Assert.isNotNull(LoanProductPlan);
        Assert.isTrue(Objects.equals(LoanProductPlan.getPlanType(), planTypeEnum.getValue()));

        LoanProductPlanArea plan = new LoanProductPlanArea();
        plan.setLoanProductPlanId(id);
        List<LoanProductPlanArea> list = loanProductPlanAreaService.list(plan);
        List<Long> idList = new ArrayList<>();
        for (LoanProductPlanArea area : list) {
            idList.add(area.getId());
        }
        // 删除之前的区域
        loanProductPlanAreaService.batchDeleteById(idList.toArray(idList.toArray(new Long[0])));
        return loanProductPlanDao.deleteById(id);
    }

    @Override
    public String testLoanProductPlan(PlanTypeEnum planTypeEnum, LoanProductPlanTestVO loanProductPlanTestVO) {
        Assert.isNotNull(planTypeEnum);

        LoanProductPlan loanProductPlan = loanProductPlanDao.getById(loanProductPlanTestVO.getId());
        Assert.isNotNull(loanProductPlan);
        Assert.isTrue(Objects.equals(loanProductPlan.getPlanType(), planTypeEnum.getValue()));

        LoanProduct loanProduct = loanProductService.getById(loanProductPlan.getLoanProductId());
        Assert.isNotNull(loanProduct);
        String url = loanProduct.getApiDataExchange();

        String phone = loanProductPlanTestVO.getPhone();
        String phoneMd5 = com.gitee.apanlh.util.algorithm.digest.MD5.create().digestToHex(phone);
        String city = loanProductPlanTestVO.getCity();
        String userName = loanProductPlanTestVO.getUserName();

        Map<String, String> data = MapUtils.newHashMap(newMap -> {
            newMap.put("reqId", UUID.randomUUID().toString());
            newMap.put("phone", phone);
            newMap.put("phoneMd5", phoneMd5);
            newMap.put("applyId", phoneMd5);
            newMap.put("city", city);
            newMap.put("userName", userName);
            newMap.put("monthlySalary", "5");
            newMap.put("sesameCredit", "4");
            newMap.put("sex", "1");
            newMap.put("realEstateInfo", "4");
            newMap.put("carInfo", "4");
            newMap.put("socialSecurity", "4");
            newMap.put("insurancePolicy", "4");
            newMap.put("career", "4");
            newMap.put("salaryPayMethod", "1");
            newMap.put("bizPubAccBankDetails", "3");
            newMap.put("bizBankDetails", "3");
            newMap.put("bizLicenseYear", "4");
            newMap.put("age", "30");
            newMap.put("overdue", "1");
            newMap.put("btLimit", "5");
            newMap.put("hbLimit", "5");
            newMap.put("creditLimit", "6");
            newMap.put("providentFund", "4");
            newMap.put("loanAmount", "3");
        });

        TestA0001 testA0001 = ClassConvertUtils.toBean(data, TestA0001.class);

        String json = JsonUtils.toJson(testA0001);

        String PV = "4987cd682c336e06142f2eb0722dfc05e5741c42df6171067c7c118d297743cc";

        AES ecb = AES.createEcb(HexUtils.decode(PV));
        String encrypt = ecb.encryptToHex(json);
        String requestBody = JsonUtils.toJson(MapUtils.newLinkedHashMap(map -> map.put("data", encrypt)));

        StringBuilder sb = new StringBuilder();
        sb.append(LocalDateTime.now().toString()).append("  [撞库]地址:").append(url).append("\n\n");
        sb.append(LocalDateTime.now().toString()).append("  [撞库]json业务数据:").append(json).append("\n\n");
        sb.append(LocalDateTime.now().toString()).append("  [撞库]请求参数:").append(requestBody).append("\n\n");

        try {
            HttpResponse build = HttpClientBuilder.builder(url, HttpMethod.POST).withBodyJson(requestBody).build();
            String response = build.getStr();
            sb.append(LocalDateTime.now().toString()).append("  [撞库]返回响应:").append(response).append("\n\n");
        } catch (Exception e) {
            sb.append(LocalDateTime.now().toString()).append("  [撞库]错误：").append(e.getMessage()).append("\n\n");
        }

        return sb.toString();
    }
}
